// Learn TypeScript:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html

export default class captureScreen {

    public static capture_to_spriteFrame(file: string = null): cc.SpriteFrame {
        if (cc.sys.platform == cc.sys.ANDROID && window["jsb"]) {
            if (file) {
                if (!file.endsWith(".png")) {
                    file += ".png"
                }
                return this.capture_to_native(file);
            } else {
                return this.capture_to_native("temp.png");
            }
        } else {
            return this.capture_to_web();
        }
    }

    static camera: cc.Camera = null; //摄像头
    public static set_camera(c: cc.Camera) {
        this.camera = c;
    }

    //////// WEB 平台 截屏, 返回截屏数据
    public static _captrue_web(): string {
        let camera: cc.Camera = this.camera || cc.director.getScene().getComponentInChildren(cc.Camera);

        let _canvas = null;
        let texture = new cc.RenderTexture();

        texture.initWithSize(cc.visibleRect.width, cc.visibleRect.height, cc["gfx"]["RB_FMT_S8"]);
        camera.targetTexture = texture;

        let width = texture.width;
        let height = texture.height;

        _canvas = document.createElement('canvas');
        _canvas.width = width;
        _canvas.height = height;

        let ctx = _canvas.getContext('2d');
        ctx.clearRect(0, 0, _canvas.width, _canvas.height);
        camera.render();
        camera.targetTexture = null;

        let data = texture.readPixels();
        // write the render data
        let rowBytes = width * 4;
        for (let row = 0; row < height; row++) {
            let srow = height - 1 - row;
            let imageData = ctx.createImageData(width, 1);
            let start = srow * width * 4;
            for (let i = 0; i < rowBytes; i++) {
                imageData.data[i] = data[start + i];
            }

            ctx.putImageData(imageData, 0, row);
        }

        return _canvas.toDataURL("image/png");
    }

    ///////////////// 截屏只截取部分区域
    public static _captrue_web_rect(rect: cc.Rect): string {
        let camera: cc.Camera = this.camera || cc.director.getScene().getComponentInChildren(cc.Camera);

        let _canvas = null;
        let texture = new cc.RenderTexture();

        texture.initWithSize(cc.visibleRect.width, cc.visibleRect.height, cc["gfx"]["RB_FMT_S8"]);
        camera.targetTexture = texture;
        camera.render();
        camera.targetTexture = null;

        let width = texture.width;
        let height = texture.height;

        
        let rect_int = new cc.Rect();
        rect_int.x = Math.floor(rect.x * width);
        rect_int.y = Math.floor(rect.y * height);
        rect_int.width = Math.floor(rect.width * width);
        rect_int.height = Math.floor(rect.height * height);

        _canvas = document.createElement('canvas');
        _canvas.width = rect_int.width;
        _canvas.height = rect_int.height;

        let ctx = _canvas.getContext('2d');
        ctx.clearRect(0, 0, _canvas.width, _canvas.height);

        let data = texture.readPixels();
        let data_diandao = this.imgData_diandao(data, width, height);
        
        let data_caiqie = this.imgData_caiqie(data_diandao, width, height, rect_int);

        let imageData = ctx.createImageData(rect_int.width, rect_int.height);
        imageData.data.set(data_caiqie);
        ctx.putImageData(imageData, 0, 0);
        
        return _canvas.toDataURL("image/png");
    }

    // /**
    //  *    图像数据 上下颠倒
    //  */
    // private static imgData_diandao(data: Uint8Array, w: number, h: number): Uint8Array {
    //     let r = new Uint8Array(data.length);
    //     let rowBytes = w * 4;
    //     for (let row = 0; row < h; row++) {
    //         let srow = h - 1 - row;
    //         let start = srow * w * 4;

    //         let b = row * w * 4;
    //         for (let i = 0; i < rowBytes; i++) {
    //             r[b + i] = data[start + i];
    //         }
    //     }
    //     return r;
    // }

    /**
     * 图像数据上下颠倒
     * @param {Uint8Array} data - 图像数据，每个像素由4个字节表示（RGBA）
     * @param {number} w - 图像宽度（像素）
     * @param {number} h - 图像高度（像素）
     * @returns {Uint8Array} - 颠倒后的图像数据
     **/
    private static imgData_diandao(data: Uint8Array, w: number, h: number): Uint8Array {
        // 检查输入参数有效性
        if (!data || w <= 0 || h <= 0) {
            throw new Error('Invalid input parameters');
        }
        // 创建用于存储颠倒后图像数据的新数组
        const flippedData = new Uint8Array(data.length);
        let srcRowIndex = 0;
        let dstRowIndex = (h - 1) * w * 4;
        for (let y = 0; y < h; ++y) {
            // 复制一行像素数据，从源数组的顶部行到目标数组的底部行
            flippedData.set(data.subarray(srcRowIndex, srcRowIndex + w * 4), dstRowIndex);
            // 更新源行索引和目标行索引
            srcRowIndex += w * 4;
            dstRowIndex -= w * 4;
        }
        return flippedData;
    }

    /**
     * 图像数据裁切
     * @param {Uint8Array} data - 图像数据，每个像素由4个字节表示（RGBA）
     * @param {number} w - 图像宽度（像素）
     * @param {number} h - 图像高度（像素）
     * @param {cc.Rect} rect - 裁切区域，以像素为单位（整数），格式为{x: x起点, y: y起点, width: 剪裁宽度, height: 剪裁高度}
     * @returns {Uint8Array} - 裁剪后的图像数据
     */
    private static imgData_caiqie(data: Uint8Array, w: number, h: number, rect: cc.Rect): Uint8Array {
        // 检查输入参数有效性
        if (!data || w <= 0 || h <= 0 || !rect || rect.width <= 0 || rect.height <= 0) {
            throw new Error('Invalid input parameters');
        }
        // 计算裁切区域相对于图像的起始位置和结束位置
        const startX = Math.floor(rect.x);
        const startY = Math.floor(rect.y);
        const endX = Math.min(startX + rect.width, w);
        const endY = Math.min(startY + rect.height, h);
        // 创建用于存储裁切后图像数据的新数组
        const croppedData = new Uint8Array(rect.width * rect.height * 4);
        let srcIndex = 0;
        let dstIndex = 0;
        for (let y = startY; y < endY; ++y) {
            for (let x = startX; x < endX; ++x) {
                // 计算源图像数据中当前像素的位置
                srcIndex = ((y * w) + x) * 4;

                // 将源图像数据中的当前像素复制到裁切后的图像数据中
                croppedData[dstIndex++] = data[srcIndex++];
                croppedData[dstIndex++] = data[srcIndex++];
                croppedData[dstIndex++] = data[srcIndex++];
                croppedData[dstIndex++] = data[srcIndex++];
            }
        }
        return croppedData;
    }

    /**
     *      截屏 获取 图片
     */
    public static capture_to_web(): cc.SpriteFrame {
        var img = document.createElement("img");
        img.src = this._captrue_web();

        let t2d = new cc.Texture2D();
        t2d.initWithElement(img);

        let spriteFrame = new cc.SpriteFrame();
        spriteFrame.setTexture(t2d);
        return spriteFrame;
    }


    /**
     *      截屏 获取 图片 base64 (WEB环境)
     */
    public static capture_to_base64(): string {
        var base64Image = this._captrue_web();
        return encodeURIComponent(base64Image.substr(base64Image.indexOf(',') + 1))
    }

    /**
     *      截屏 获取 图片 blob
     */
    public static capture_to_Blob(): Blob {
        var dataURI = this._captrue_web();

        let arr = dataURI.split(',');
        let byteString = atob(arr[1]);
        let mimeString = arr[0].split(':')[1].split(';')[0];
        let ab = new ArrayBuffer(byteString.length);
        let ia = new Uint8Array(ab);
        for (let i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
        return new Blob([ab], { type: mimeString });
    }

    public static capture_down_file(fileName: string) {
        let b: Blob = this.capture_to_Blob();

        // 创建隐藏的可下载链接
        var hiddenLink = document.createElement('a');
        hiddenLink.style.display = 'none';
        document.body.appendChild(hiddenLink);

        // 为Blob对象创建一个指向其内部数据的URL
        var url = URL.createObjectURL(b);

        // 设置链接的href属性和download属性
        hiddenLink.href = url;
        hiddenLink.download = fileName;

        // 触发点击以开始下载
        hiddenLink.click();

        // 下载完成后清理资源
        setTimeout(function () {
            document.body.removeChild(hiddenLink);
            window.URL.revokeObjectURL(url); // 释放内存中的Blob引用
        }, 0);
    }

    public static capture_to_native(file_name: string): cc.SpriteFrame {
        let camera: cc.Camera = cc.director.getScene().getComponentInChildren(cc.Camera);

        let texture = new cc.RenderTexture();
        texture.initWithSize(cc.visibleRect.width, cc.visibleRect.height, cc["gfx"]["RB_FMT_S8"]);
        camera.targetTexture = texture;
        camera.render();
        camera.targetTexture = null;
        let filpYImage = (data, width, height) => {
            // create the data array
            let picData = new Uint8Array(width * height * 4);
            let rowBytes = width * 4;
            for (let row = 0; row < height; row++) {
                let srow = height - 1 - row;
                let start = srow * width * 4;
                let reStart = row * width * 4;
                // save the piexls data
                for (let i = 0; i < rowBytes; i++) {
                    picData[reStart + i] = data[start + i];
                }
            }
            return picData;
        }

        let data = texture.readPixels();

        let _width = texture.width;
        let _height = texture.height;
        let picData = filpYImage(data, _width, _height);

        let t2d = new cc.Texture2D();
        t2d.initWithData(picData, texture.getPixelFormat(), _width, _height);

        let spriteFrame = new cc.SpriteFrame();
        spriteFrame.setTexture(t2d);

        if (file_name) {
            let filePath = jsb.fileUtils.getWritablePath() + file_name; //拿到可写路径，将图片保存在本地，可以在ios端或者java端读取该文件

            let success = jsb["saveImageData"](picData, _width, _height, filePath)
            if (success) {
                console.log("save image data success, file: " + filePath);
            }
            else {
                console.error("save image data failed!");
            }
        }
        return spriteFrame;
    }



}
